 public class BMPManipulatorGroup extends BMPManipulator
{
	 
	int dim;
	
	public BMPManipulatorGroup(String file)
	{
		super(file);
	}

	/**
	 * normalizeMask -- "normalize" the given mask such that sum of the
	 *   values in the mask is 1
	 * @param mask The mask to normalize
	 */
	public static void normalizeMask(double mask[][])
	{
		//check whether the 2D array is square
		int dim = mask.length;
		for (int i=0; i<dim; i++){
			if (mask[i].length != dim || (mask[i].length%2 == 0))
				throw new IllegalArgumentException("the input mask should be square and odd side length!");
		}
		
        //accumulate sum of every element
		double sum = 0;
		
		for (int i=0; i< dim; i++){
			for (int j=0; j<dim; j++){
				if (mask[i][j] < 0 )
					throw new IllegalArgumentException("the element of the mask should not be negtive!!");
				sum = sum + mask[i][j];
			}
		}
		
		// normalize the mask 
		for (int i=0; i< dim; i++){
			for (int j=0; j<dim; j++){
				mask[i][j] /= sum;
			}
		}
		
		//System.out.println("sum = " + sum);
		print2DArray(mask);
	}
	
	/**
	 * print2DArray -- print a abitrary 2D array
	 * @param mask double type 2D array
	 */
	private static void print2DArray(double mask[][]){
		for (int i=0; i<mask.length; i++){
			System.out.println("");
			
			for (int j=0; j<mask[i].length; j++){
				System.out.print(mask[i][j] + "  ");
			}
		
		}
		System.out.println("");
	}
	
	/**
	 * applyMask -- normalize and then apply the given mask to the stored
	 *   image by performing a two-dimensional convolution
	 *   (see assignment for details)
	 * @param mask The mask to apply
	 */
	public void applyMask(double mask[][])
	{
		normalizeMask(mask);
		dim = mask.length;
		int index[];
		
		for(int a = 0; a < height; a++){
			for(int b = 0; b < width; b++){
				
				int redSum = 0;
				int greenSum = 0;
				int blueSum = 0;
				
				for(int j = 0; j < dim; j++){
					for(int k = 0; k < dim; k++){
						
						//get the index in the image array
						index = maskIndex2ImageIndex(b,a,k,j);
						
						try{
							if (index[0] < 0 || index[0] >= width || index[1] < 0 || index[1] >= height)
								throw new ArrayIndexOutOfBoundsException();
							
							// accumulate the sum of adjacent element, respectly
							redSum = redSum + (int)((int)(bytes[indexRed(index[1],index[0])]) * mask[k][j]);
							
							greenSum = greenSum + (int) ((int)(bytes[indexGreen(index[1],index[0])]) * mask[k][j]);
							
							blueSum = blueSum + (int) ((int)(bytes[indexBlue(index[1],index[0])]) * mask[k][j]);
								
						}catch (ArrayIndexOutOfBoundsException e){
							// if there is no according element in the image array, just weight it 0
							// so I do nothing here
							/*System.out.println("k= " + k);
							System.out.println("j= " + j);
							System.out.println("index[0]= " +index[0]);
							System.out.println("index[1]= " +index[1]);
							System.out.println("b= " + b);
							System.out.println("a= " + a);*/
						}
					}
				}
				
				
				// use the sum to update the the element in the image array
				
				bytes[indexRed(a,b)] = (byte) redSum;
				
				bytes[indexGreen(a,b)] = (byte) greenSum;
				
				bytes[indexBlue(a,b)] = (byte) blueSum;
			}	
		}
		
	}
	

	
	/**
	 * maskIndex2ImageIndex -- get the image index from mask index 
	 * @param xCenter x index of center element
	 * @param yCenter y index of center element
	 * @param xMask x index of mask element
	 * @param yMask y index of mask element
	 * @return the index of in the 2D image array
	 */
	public int[] maskIndex2ImageIndex(int xCenter,int yCenter,int xMask,int yMask){
		int[] index = new int[2];
		
		index[0] = xCenter + (xMask - dim/2);
		index[1] = yCenter + (yMask - dim/2);
		
		return index;		
	}
	
	/**
	 * blur -- apply a blurring filter to the stored image
	 */
	public void blur()
	{
		double mask[][] = {{1, 3, 1}, {3, 5, 3}, {1, 3, 1}};
		//double mask[][] = {{0, 0, 0}, {0, 1, 0}, {0, 0, 0}};
		
		//double mask[][] = {{1, 2, 3, 2, 1}, {2, 3, 4, 3, 2}, {3, 4, 5, 4, 3}, {2, 3, 4, 3, 2}, {1, 2, 3, 2, 1}};
		print2DArray(mask);
		
		applyMask(mask);
	}
	
	/**
	 * A sample driver -- you will not be graded on this method, so
	 * you may modify it as necessary to test your program 
	 */
	public static void main(String[] args)
	{
		BMPManipulatorGroup m = new BMPManipulatorGroup("../guna.bmp");
		m.blur();
		
		m.writeImage("appliedmask.bmp");
	}
	
}
